﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;
using System.Web.Http.Routing;
using WooCoo.Tools;

namespace WooCoo.DataPortal.WebHost.ODataServer
{
    public class ODataPortalActionSelector : IHttpActionSelector
    {
        private readonly IHttpActionSelector _innerSelector;

        /// <summary>构造器.</summary>
		/// <param name="innerSelector">The inner controller selector to call.</param>
        public ODataPortalActionSelector(IHttpActionSelector innerSelector)
		{
			if (innerSelector == null)
			{
				throw Error.ArgumentNull("innerSelector");
			}
			this._innerSelector = innerSelector;
		}

        /// <summary>Returns a map, keyed by action string, of all <see cref="T:System.Web.Http.Controllers.HttpActionDescriptor" /> that the selector can select. This is primarily called by <see cref="T:System.Web.Http.Description.IApiExplorer" /> to discover all the possible actions in the controller.</summary>
        /// <returns>A map of <see cref="T:System.Web.Http.Controllers.HttpActionDescriptor" /> that the selector can select, or null if the selector does not have a well-defined mapping of <see cref="T:System.Web.Http.Controllers.HttpActionDescriptor" /> .</returns>
        /// <param name="controllerDescriptor">The controller descriptor.</param>
        /// <exception cref="T:System.NotImplementedException"></exception>
        public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
        {
            return this._innerSelector.GetActionMapping(controllerDescriptor);
        }

        /// <summary>Selects an action for the <see cref="T:System.Web.Http.Controllers.ApiControllerActionSelector" /> .</summary>
        /// <returns>The selected action.</returns>
        /// <param name="controllerContext">The controller context.</param>
        public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
        {
            if (controllerContext == null)
            {
                throw Error.ArgumentNull("controllerContext");
            }
            HttpRequestMessage request = controllerContext.Request;
            ODataPath oDataPath = request.GetODataPath();
            IEnumerable<IODataRoutingConvention> oDataRoutingConventions = request.GetODataRoutingConventions();
            IHttpRouteData routeData = controllerContext.RouteData;
            if (oDataPath == null || oDataRoutingConventions == null || routeData.Values.ContainsKey(ODataRouteConstants.Action))
            {
                return this._innerSelector.SelectAction(controllerContext);
            }
            ILookup<string, HttpActionDescriptor> actionMapping = this._innerSelector.GetActionMapping(controllerContext.ControllerDescriptor);
            foreach (IODataRoutingConvention current in oDataRoutingConventions)
            {
                string actionName = current.SelectAction(oDataPath, controllerContext, actionMapping);
                if (actionName != null)
                {
                    routeData.Values[ODataRouteConstants.Action] = actionName;                    
                    return this._innerSelector.SelectAction(controllerContext);
                }
            }
            throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound, string.Format("No matching resource found for {0}", controllerContext.Request.RequestUri)));
            //    Error.Format(SRResources.NoMatchingResource, new object[]
            //{
            //    controllerContext.Request.RequestUri
            //}), Error.Format(SRResources.NoRoutingHandlerToSelectAction, new object[]
            //{
            //    oDataPath.PathTemplate
            //})));
        }
    }
}
